using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Pay.Core {
	/// <summary>
	/// 通用类型扩展方法类
	/// </summary>
	public static class ObjectExtensions {
		/// <summary>
		/// 把对象类型转化为指定类型，转化失败时返回该类型默认值
		/// </summary>
		/// <typeparam name="T"> 动态类型 </typeparam>
		/// <param name="value"> 要转化的源对象 </param>
		/// <returns> 转化后的指定类型的对象，转化失败返回类型的默认值 </returns>
		public static T CastTo<T>(this object value) {
			object result;
			Type type = typeof(T);
			try {
				if (type.IsEnum) {
					result = Enum.Parse(type, value.ToString());
				} else if (type == typeof(Guid)) {
					result = Guid.Parse(value.ToString());
				} else {
					result = Convert.ChangeType(value, type);
				}
			} catch {
				result = default(T);
			}

			return (T)result;
		}

		/// <summary>
		/// 把对象类型转化为指定类型，转化失败时返回指定的默认值
		/// </summary>
		/// <typeparam name="T"> 动态类型 </typeparam>
		/// <param name="value"> 要转化的源对象 </param>
		/// <param name="defaultValue"> 转化失败返回的指定默认值 </param>
		/// <returns> 转化后的指定类型对象，转化失败时返回指定的默认值 </returns>
		public static T CastTo<T>(this object value, T defaultValue) {
			object result;
			Type type = typeof(T);
			try {
				result = type.IsEnum ? Enum.Parse(type, value.ToString()) : Convert.ChangeType(value, type);
			} catch {
				result = defaultValue;
			}
			return (T)result;
		}

		public static IEnumerable<T> CopyToList<T>(this IEnumerable<T> obj) {
			var list = obj.ToList();
			return CopyTo(list) as IEnumerable<T>;
		}

		public static object CopyTo(this object obj) {
			MemoryStream stream = new MemoryStream();
			BinaryFormatter formatter = new BinaryFormatter();
			formatter.Serialize(stream, obj);
			stream.Position = 0;
			return formatter.Deserialize(stream);
			//Object targetDeepCopyObj;
			//Type targetType = obj.GetType();
			////值类型
			//if (targetType.IsValueType == true) {
			//    targetDeepCopyObj = obj;
			//}
			////引用类型 
			//else {
			//    targetDeepCopyObj = System.Activator.CreateInstance(targetType);   //创建引用对象 
			//    MemberInfo[] memberCollection = obj.GetType().GetMembers();

			//    foreach (MemberInfo member in memberCollection) {
			//        if (member.MemberType == MemberTypes.Field) {
			//            FieldInfo field = (FieldInfo)member;
			//            Object fieldValue = field.GetValue(obj);
			//            if (fieldValue is ICloneable) {
			//                field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone());
			//            } else {
			//                field.SetValue(targetDeepCopyObj, CopyTo(fieldValue));
			//            }

			//        } else if (member.MemberType == MemberTypes.Property) {
			//            PropertyInfo myProperty = (PropertyInfo)member;
			//            MethodInfo info = myProperty.GetSetMethod(false);
			//            if (info != null) {
			//                object propertyValue = myProperty.GetValue(obj, null);
			//                if (propertyValue is ICloneable) {
			//                    myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null);
			//                } else {
			//                    myProperty.SetValue(targetDeepCopyObj, CopyTo(propertyValue), null);
			//                }
			//            }

			//        }
			//    }
			//}
			//return targetDeepCopyObj;
		}
		/// <summary> 
		/// 将一个object对象序列化，返回一个byte[]         
		/// </summary> 
		/// <param name="obj">能序列化的对象</param>         
		/// <returns></returns> 
		public static byte[] ObjectToBytes(this object obj) {
			using (MemoryStream ms = new MemoryStream()) {
				IFormatter formatter = new BinaryFormatter();
				formatter.Serialize(ms, obj);
				return ms.GetBuffer();
			}
		}

		/// <summary> 
		/// 将一个序列化后的byte[]数组还原         
		/// </summary>
		/// <param name="Bytes"></param>         
		/// <returns></returns> 
		public static object BytesToObject(this byte[] Bytes) {
			using (MemoryStream ms = new MemoryStream(Bytes)) {
				IFormatter formatter = new BinaryFormatter();
				return formatter.Deserialize(ms);
			}
		}

        /// <summary>
        /// 对象属性拷贝
        /// </summary>
        /// <typeparam name="TEntity1"></typeparam>
        /// <typeparam name="TEntity2"></typeparam>
        /// <param name="eny1"></param>
        /// <param name="eny2"></param>
        /// <param name="excludeProps"></param>
        public static void ToCopyProperty<TEntity1, TEntity2>(this TEntity1 eny1, TEntity2 eny2, List<string> excludeProps = null) where TEntity1 : class
        {
            if (eny1 == null || eny2 == null) return;
            var curType = eny1.GetType();
            var tarType = eny2.GetType();
            var propertyList = (from x in curType.GetProperties()
                                join y in tarType.GetProperties() on x.Name equals y.Name
                                select new
                                {
                                    cur = x,
                                    tar = y
                                });

            foreach (var p in propertyList)
            {
                try
                {
                    if (excludeProps != null && excludeProps.Contains(p.tar.Name)) continue;
                    if (!p.tar.CanWrite ||
                        (p.tar.PropertyType.IsGenericType && !p.tar.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))) continue;
                    p.tar.SetValue(eny2, p.cur.GetValue(eny1, null), null);
                }
                catch (Exception) { continue; }
            }
        }
    }
}